package com.cloud.annex.service;

import cn.hutool.extra.qrcode.QrCodeUtil;
import com.cloud.annex.AnnexConfiguration;
import com.cloud.annex.mapper.MinioMapper;
import com.cloud.common.constants.GlobalConstants;
import com.cloud.common.domain.Result;
import com.cloud.common.domain.vo.SvgParam;
import com.cloud.common.utils.ImageUtils;
import com.cloud.exception.CommonException;
import com.cloud.utils.SVGUtils;
import com.cloud.utils.ServletUtils;
import com.cloud.utils.ToolUtils;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class MinioService {

    @Autowired
    private MinioMapper minioMapper;

    @Autowired
    private AnnexConfiguration annexConfiguration;

    /**
     * 文件上传返回访问URL
     *
     * @param isNewName  是否创建新名称 true创建新名称
     * @param bucketName 存储桶
     * @param file
     * @return
     */
    public Map<String, Object> saveUploadAnnex(boolean isNewName, String bucketName,
                                               String annexName, MultipartFile file) {
        Map<String, Object> mapAnnex = new HashMap<>();
        try {
            StringBuffer fileName = new StringBuffer();
            String timePrefix = annexName + "/" + ToolUtils.getDataUrlFormat();
            String oldName = file.getOriginalFilename();
            String suffix = oldName.substring(oldName.lastIndexOf("."));
            if (isNewName) {
                fileName.append(timePrefix).append("/").append(ToolUtils.getUuid()).append(suffix);
            } else {
                fileName.append(timePrefix).append("/").append(oldName);
            }
            // 保存文件到Minio 文件服务中
            minioMapper.putObject(bucketName, file, fileName.toString());
            String url = null;
            if (annexConfiguration.getGingType()) {
                url = minioMapper.getObjectUrl(bucketName, fileName.toString());
            } else {
                url = minioMapper.getPreSignObjectUrl(bucketName,
                        fileName.toString(), annexConfiguration.getMemoryTime());
            }
            mapAnnex.put("name", file.getOriginalFilename());
            mapAnnex.put("address", fileName);
            mapAnnex.put("suffix", suffix);
            mapAnnex.put("url", url);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return mapAnnex;
    }

    /**
     * 图像上传压缩文件大小并返回访问URL
     *
     * @param isNewName  是否创建新名称 true创建新名称
     * @param bucketName 存储桶
     * @param file
     */
    public Map<String, Object> zipUploadImage(boolean isNewName, String bucketName, MultipartFile file) {
        Map<String, Object> mapAnnex = new HashMap<>();
        try {
            StringBuffer fileName = new StringBuffer();
            String timePrefix = GlobalConstants.annexNodeName + "/" + ToolUtils.getDataUrlFormat();
            String oldName = file.getOriginalFilename();
            String suffix = oldName.substring(oldName.lastIndexOf("."));
            if (isNewName) {
                fileName.append(timePrefix).append("/").append(ToolUtils.getUuid()).append(suffix);
            } else {
                fileName.append(timePrefix).append("/").append(oldName);
            }
            // 压缩图片并转为输入流IO
            InputStream inputStream = ImageUtils.getInputStream(ImageUtils.compress(ImageUtils.compress(ImageIO
                    .read(file.getInputStream()))), ImageUtils.getFileExtention(file.getOriginalFilename()));
            // 通过InputStream 上传图片对象信息
            minioMapper.putObject(bucketName, fileName.toString(), inputStream, file.getContentType());
            String url = null;
            if (annexConfiguration.getGingType()) {
                url = minioMapper.getObjectUrl(bucketName, fileName.toString());
            } else {
                url = minioMapper.getPreSignObjectUrl(bucketName,
                        fileName.toString(), annexConfiguration.getMemoryTime());
            }
            mapAnnex.put("url", url);
            mapAnnex.put("name", fileName);
            mapAnnex.put("suffix", suffix);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return mapAnnex;
    }

    /**
     * 单文件上传
     *
     * @param file
     * @param isNewName 是否创建新名称 true创建新名称
     * @return
     */
    public Result upload(MultipartFile file, boolean isNewName) {
        String bucketName = annexConfiguration.getBucketName();
        // 判断存储桶是否存在
        if (minioMapper.bucketExists(bucketName)) {
            return Result.success("操作成功", saveUploadAnnex(isNewName,
                    bucketName, GlobalConstants.annexNodeName, file));
        } else {
            return Result.message(CommonException.BUCKET_NO_EXITS.getCode(),
                    CommonException.BUCKET_NO_EXITS.getMsg());
        }
    }

    /**
     * 系统图标上传
     *
     * @param file
     * @param isNewName 是否创建新名称 true创建新名称
     * @return
     */
    public Result uploadIcon(MultipartFile file, boolean isNewName) {
        String bucketName = annexConfiguration.getBucketName();
        // 判断存储桶是否存在
        if (minioMapper.bucketExists(bucketName)) {
            return Result.success("操作成功", saveUploadAnnex(isNewName,
                    bucketName, GlobalConstants.iconNodeName, file));
        } else {
            return Result.message(CommonException.BUCKET_NO_EXITS.getCode(),
                    CommonException.BUCKET_NO_EXITS.getMsg());
        }
    }

    /**
     * 多文件上传
     *
     * @param file
     * @param isNewName 是否创建新名称 true创建新名称
     * @return
     */
    public Result moreUpload(List<MultipartFile> file, boolean isNewName) {
        List<Map<String, Object>> list = new ArrayList<>();
        String bucketName = annexConfiguration.getBucketName();
        if (minioMapper.bucketExists(bucketName)) {
            file.forEach((var) -> {
                list.add(saveUploadAnnex(isNewName, bucketName, GlobalConstants.annexNodeName, var));
            });
        } else {
            return Result.message(CommonException.BUCKET_NO_EXITS.getCode(),
                    CommonException.BUCKET_NO_EXITS.getMsg());
        }
        if (list.size() > 0) {
            return Result.success("操作成功", list);
        } else {
            return Result.error("操作失败：请重新上传");
        }
    }

    /**
     * 图片压缩上传
     *
     * @param file
     * @param isNewName 是否创建新名称 true创建新名称
     * @return
     */
    public Result uploadZipImage(MultipartFile file, boolean isNewName) {
        String bucketName = annexConfiguration.getBucketName();
        if (minioMapper.bucketExists(bucketName)) {
            return Result.success("操作成功", zipUploadImage(isNewName, bucketName, file));
        } else {
            return Result.message(CommonException.BUCKET_NO_EXITS.getCode(),
                    CommonException.BUCKET_NO_EXITS.getMsg());
        }
    }

    /**
     * 文件下载
     *
     * @param fileName 上传文件名称
     * @return
     */
    public Result download(String fileName) {
        HttpServletResponse response = ServletUtils.getResponse();
        String bucketName = annexConfiguration.getBucketName();
        if (minioMapper.bucketExists(bucketName)) {
            minioMapper.downloadFile(bucketName, fileName, null, response);
        } else {
            return Result.message(CommonException.BUCKET_NO_EXITS.getCode(),
                    CommonException.BUCKET_NO_EXITS.getMsg());
        }
        return Result.success("操作成功");
    }

    /**
     * 多文件下载
     *
     * @param zipName 文件压缩后名称
     * @param urlList 上传文件名称集合
     * @return
     */
    public Result moreDownload(String zipName, List<String> urlList) {
        HttpServletResponse response = ServletUtils.getResponse();
        String bucketName = annexConfiguration.getBucketName();
        if (minioMapper.bucketExists(bucketName)) {
            minioMapper.downloadFiles(bucketName, zipName, urlList, response);
        } else {
            return Result.message(CommonException.BUCKET_NO_EXITS.getCode(),
                    CommonException.BUCKET_NO_EXITS.getMsg());
        }
        return Result.success("操作成功");
    }

    /**
     * 文件删除
     *
     * @param fileName 上传文件名称
     * @return
     */
    public Result remove(String fileName) {
        String bucketName = annexConfiguration.getBucketName();
        if (minioMapper.bucketExists(bucketName)) {
            if (minioMapper.removeObject(bucketName, fileName)) {
                return Result.success("操作成功");
            } else {
                return Result.error("操作失败");
            }
        } else {
            return Result.message(CommonException.BUCKET_NO_EXITS.getCode(),
                    CommonException.BUCKET_NO_EXITS.getMsg());
        }
    }

    /**
     * Minio创建存储桶
     *
     * @param bucketName 存储桶
     * @return
     */
    public Result addBucket(String bucketName) {
        if (minioMapper.makeBucket(bucketName)) {
            return Result.success("操作成功");
        } else {
            return Result.error("操作失败");
        }
    }

    /**
     * Minio设置桶策略
     *
     * @param bucketName 存储桶
     * @return
     */
    public Result bucketPolicy(String bucketName) {
        if (minioMapper.bucketExists(bucketName)) {
            if (minioMapper.setBucketPolicy(bucketName)) {
                return Result.success("操作成功");
            } else {
                return Result.error("操作失败");
            }
        } else {
            return Result.message(CommonException.BUCKET_NO_EXITS.getCode(),
                    CommonException.BUCKET_NO_EXITS.getMsg());
        }
    }

    /**
     * Feign调用（查询上传附件路径）
     *
     * @param fileName 上传文件名称
     * @return
     */
    public Result getInAnnexUrl(String fileName) {
        try {
            String bucketName = annexConfiguration.getBucketName();
            String objectUrl = minioMapper.getObjectUrl(bucketName, fileName);
            return Result.success("查询成功", objectUrl);
        } catch (Exception e) {
            return Result.error("查询附件Url失败:" + e);
        }
    }

    /**
     * 根据SVG地址转化PNG地址
     *
     * @param svgParam
     * @return
     */
    public Result svgInvertUrl(SvgParam svgParam) {
        String bucketName = annexConfiguration.getBucketName();
        String svgName = "image" + "/" + ToolUtils.getUuid() + ".png";
        ByteArrayOutputStream outputStream = SVGUtils.getOutputStream(svgParam);
        if (ObjectUtils.isNotEmpty(outputStream)) {
            InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
            // SVG转PNG输入流并添加Minio
            if (ObjectUtils.isNotEmpty(inputStream)) {
                minioMapper.putObject(bucketName, svgName, inputStream, "image/png");
            }
        }
        String pathUrl = null;
        if (annexConfiguration.getGingType()) {
            pathUrl = minioMapper.getObjectUrl(bucketName, svgName);
        } else {
            pathUrl = minioMapper.getPreSignObjectUrl(bucketName, svgName,
                    annexConfiguration.getMemoryTime());
        }
        return Result.success("操作成功", pathUrl);
    }

    public Result getQRCodeUrl(String content) {
        String bucketName = annexConfiguration.getBucketName();
        StringBuilder url = new StringBuilder();
        String timePrefix = ToolUtils.getDataUrlFormat();
        url.append(timePrefix).append("/").append(ToolUtils.getUuid()).append(".png");
        byte[] bytes = QrCodeUtil.generatePng(content, 300, 300);
        InputStream inputStream = null;
        if (ObjectUtils.isNotEmpty(bytes)) {
            inputStream = new ByteArrayInputStream(bytes);
        }
        minioMapper.putObject(bucketName, url.toString(), inputStream, "image/png");
        String pathUrl = null;
        if (annexConfiguration.getGingType()) {
            pathUrl = minioMapper.getObjectUrl(bucketName, url.toString());
        } else {
            pathUrl = minioMapper.getPreSignObjectUrl(bucketName, url.toString(),
                    annexConfiguration.getMemoryTime());
        }
        return Result.success("操作成功", pathUrl);
    }

}
